﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Xml;
using DestroyIt;
using DG.DemiEditor;
using Gameplay.PVE.Survivor;
using ImageEffects;
using NodeCanvas.Tasks.Actions;
using OWL.Rendering.HRP;
using UnityEditor;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.AssetStandardProcessors;
using UnityEngine.Playables;
using UnityEngine.Rendering;
using UnityEngine.Timeline;
using Yoozoo.Gameplay.City.GpuSkinning.Editor;
using Yoozoo.Gameplay.RTS;
using Yoozoo.HRP.Runtime;
using Yoozoo.Managers.ResourceManagerV2.Framework;
using Object = UnityEngine.Object;

public class BattleTools
{
    [MenuItem("Assets/俯视角射击/角色材质", false, 1)]
    public static void ResetMaterial()
    {
        var objects = Selection.objects;
        for (int i = 0; i < objects.Length; i++)
        {
            var obj = GameObject.Instantiate(objects[i] as GameObject);
            var skinnedMeshRenderers = obj.GetComponentsInChildren<SkinnedMeshRenderer>();
            for (int j = 0; j < skinnedMeshRenderers.Length; j++)
            {
                var skinnedMeshRender = skinnedMeshRenderers[j];
                var materials = skinnedMeshRender.sharedMaterials;
                var newMaterials = new List<Material>();
                var hasOcclusion = false;
                var hasShadow = false;
                for (int k = 0; k < materials.Length; k++)
                {
                    var mat = materials[k];
                    if (mat.shader.name.Contains("ClothOcclusion"))
                    {
                        hasOcclusion = true;
                    }
                    else if (mat.shader.name.Contains("ModelMeshShadow"))
                    {
                        hasShadow = true;
                    }
                    newMaterials.Add(mat);
                }

                if (!hasShadow)
                {
                    newMaterials.Add(AssetDatabase.LoadAssetAtPath<Material>("Assets/ResourcesAssets/Pve/Materials/mat_model_shadow.mat"));
                }

                if (!hasOcclusion && obj.name.Contains("survivor_hero_"))
                {
                    newMaterials.Add(AssetDatabase.LoadAssetAtPath<Material>("Assets/ResourcesAssets/Pve/Survivor/Materials/mat_survivor_occlusion.mat"));
                }
                skinnedMeshRender.sharedMaterials = newMaterials.ToArray();
                skinnedMeshRender.shadowCastingMode = ShadowCastingMode.Off;
            }
            var meshRenderers = obj.GetComponentsInChildren<MeshRenderer>();
            for (int j = 0; j < meshRenderers.Length; j++)
            {
                var meshRenderer = meshRenderers[j];
                var materials = meshRenderer.sharedMaterials;
                var newMaterials = new List<Material>();
                var hasOcclusion = false;
                var hasShadow = false;
                for (int k = 0; k < materials.Length; k++)
                {
                    var mat = materials[k];
                    if (mat.shader.name.Contains("ClothOcclusion"))
                    {
                        hasOcclusion = true;
                    }
                    else if (mat.shader.name.Contains("ModelMeshShadow"))
                    {
                        hasShadow = true;
                    }
                    newMaterials.Add(mat);
                }

                if (!hasShadow)
                {
                    newMaterials.Add(AssetDatabase.LoadAssetAtPath<Material>("Assets/ResourcesAssets/Pve/Materials/mat_model_shadow.mat"));
                }

                if (!hasOcclusion && obj.name.Contains("survivor_hero_"))
                {
                    newMaterials.Add(AssetDatabase.LoadAssetAtPath<Material>("Assets/ResourcesAssets/Pve/Survivor/Materials/mat_survivor_occlusion.mat"));
                }
                meshRenderer.sharedMaterials = newMaterials.ToArray();
                meshRenderer.shadowCastingMode = ShadowCastingMode.Off;
            }
            var path = AssetDatabase.GetAssetPath(objects[i]);
            PrefabUtility.SaveAsPrefabAsset(obj, path);
            AssetDatabase.SaveAssets();
            GameObject.DestroyImmediate(obj);
        }
        AssetDatabase.Refresh();
    }

    [MenuItem("Assets/俯视角射击/GpuSkinning", false, 10)]
    public static void ExportGpuSkinning()
    {
        GpuSkinningAnimatorCreator.CollectSurvivorPrefabInfo();
        var objects = Selection.objects;
        for (int i = 0; i < objects.Length; i++)
        {
            GpuSkinningAnimatorCreator.ExportSingle(objects[i].name);
        }
    }
    
    [MenuItem("Assets/俯视角射击/HpStateDisplay", false, 10)]
    public static void CreateHpStateDisplay()
    {
        var objects = Selection.objects;
        for (int i = 0; i < objects.Length; i++)
        {
            var obj = GameObject.Instantiate(objects[i] as GameObject);
            var hpStateDisplay = obj.GetComponent<HpStateDisplay>();
            if (hpStateDisplay == null)
            {
                var mapObstacle = obj.GetComponentInChildren<MapObstacleData>();
                if (mapObstacle != null)
                {
                    obj.AddComponent<HpStateDisplay>().CopyFromObstacle(mapObstacle);
                }
            }
            var path = AssetDatabase.GetAssetPath(objects[i]);
            PrefabUtility.SaveAsPrefabAsset(obj, path);
            AssetDatabase.SaveAssets();
            GameObject.DestroyImmediate(obj);
        }
        AssetDatabase.Refresh();
    }
    
    [MenuItem("Assets/俯视角射击/ClearMapObject", false, 10)]
    public static void ClearMapObject()
    {
        var objects = Selection.objects;
        for (int i = 0; i < objects.Length; i++)
        {
            var obj = GameObject.Instantiate(objects[i] as GameObject);
            var destructible = obj.GetComponentsInChildren<Destructible>();
            for (int j = 0; j < destructible.Length; j++)
            {
                GameObject.DestroyImmediate(destructible[j]);
            }
            var rigidbody = obj.GetComponentsInChildren<Rigidbody>();
            for (int j = 0; j < rigidbody.Length; j++)
            {
                GameObject.DestroyImmediate(rigidbody[j]);
            }
            //改造LodGroup
            /*var lodGroups = obj.GetComponentsInChildren<LODGroup>();
            if (lodGroups != null)
            {
                var destroyList = new List<GameObject>();
                for (int j = 0; j < lodGroups.Length; j++)
                {
                    var group = lodGroups[j];
                    var lods = group.GetLODs();
                    for (int k = 0; k < lods.Length - 1; k++)
                    {
                        var lod = lods[k];
                        var renderers = lod.renderers;
                        for (int l = 0; l < renderers.Length; l++)
                        {
                            var renderer = renderers[l];
                            destroyList.Add(renderer.gameObject);
                        }
                    }
                    GameObject.DestroyImmediate(group);
                }
                for (int j = 0; j < destroyList.Count; j++)
                {
                    GameObject.DestroyImmediate(destroyList[j]);
                }
            }
            var prefabMeshRenderCache = obj.GetComponentInChildren<PrefabMeshRenderCache>();
            if (prefabMeshRenderCache != null)
            {
                MeshRenderer[] rs = obj.GetComponentsInChildren<MeshRenderer>();
                prefabMeshRenderCache.MeshRenderers = rs != null ? rs.ToList() : new List<MeshRenderer>();
            }*/
            
            var path = AssetDatabase.GetAssetPath(objects[i]);
            PrefabUtility.SaveAsPrefabAsset(obj, path);
            AssetDatabase.SaveAssets();
            GameObject.DestroyImmediate(obj);
        }
        AssetDatabase.Refresh();
    }

    [MenuItem("Assets/俯视角射击/清理Timeline上无用的引用", false, 10)]
    public static void ClearTimeline()
    {
        if (!(Selection.activeObject is GameObject playableDirectorObj))
        {
            UnityEngine.Debug.LogError("Invalid selection. Please select a GameObject with a PlayableDirector.");
            return;
        }
        var playableDirector = playableDirectorObj.GetComponent<PlayableDirector>();
        if (playableDirector == null)
        {
            UnityEngine.Debug.LogError("No PlayableDirector component found on the selected GameObject.");
            return;
        }
        ClearExposedReference(playableDirector);
        AssetDatabase.SaveAssets();
        AssetDatabase.Refresh();
    }
    
    [MenuItem("Assets/俯视角射击/复制Timeline", false, 10)]
    public static void DupTimeline()
    {
        if (!(Selection.activeObject is GameObject playableDirectorObj))
        {
            Debug.LogError("Invalid selection. Please select a GameObject with a PlayableDirector.");
            return;
        }

        var playableDirector = playableDirectorObj.GetComponent<PlayableDirector>();
        if (playableDirector == null)
        {
            Debug.LogError("No PlayableDirector component found on the selected GameObject.");
            return;
        }

        var timelineAsset = playableDirector.playableAsset as TimelineAsset;
        if (timelineAsset == null)
        {
            Debug.LogError("Selected GameObject does not have a TimelineAsset.");
            return;
        }

        var newObject = GameObject.Instantiate(Selection.activeObject as GameObject);
        playableDirector = newObject.GetComponent<PlayableDirector>();
        
        var path = AssetDatabase.GetAssetPath(timelineAsset);
        var newPath = path.Replace(".playable", "(Clone).playable");
        if (!AssetDatabase.CopyAsset(path, newPath))
        {
            Debug.LogError("Couldn't clone asset.");
            return;
        }

        // Copy Bindings
        var newTimelineAsset = AssetDatabase.LoadMainAssetAtPath(newPath) as TimelineAsset;
        if (newTimelineAsset == null)
        {
            Debug.LogError("Failed to load cloned timeline asset.");
            return;
        }
        var oldBindings = timelineAsset.outputs.ToArray();
        var newBindings = newTimelineAsset.outputs.ToArray();
        for (int i = 0; i < oldBindings.Length; i++)
        {
            playableDirector.playableAsset = timelineAsset;
            var boundTo = playableDirector.GetGenericBinding(oldBindings[i].sourceObject);

            playableDirector.playableAsset = newTimelineAsset;
            playableDirector.SetGenericBinding(newBindings[i].sourceObject, boundTo);
        }

        // Copy Exposed References
        playableDirector.playableAsset = newTimelineAsset;
        foreach (var newTrackAsset in newTimelineAsset.GetRootTracks())
        {
            foreach (var newClip in newTrackAsset.GetClips())
            {
                foreach (var fieldInfo in newClip.asset.GetType()
                             .GetFields(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly))
                {
                    if (fieldInfo.FieldType.IsGenericType &&
                        fieldInfo.FieldType.GetGenericTypeDefinition() == typeof(ExposedReference<>))
                    {
                        var exposedReference = fieldInfo.GetValue(newClip.asset);
                        var oldExposedName =
                            (PropertyName)fieldInfo.FieldType.GetField("exposedName").GetValue(exposedReference);

                        // Fetch Old Exposed Value
                        if (!playableDirector.GetReferenceValue(oldExposedName, out bool isValid))
                        {
                            //playableDirector.ClearReferenceValue(oldExposedName);
                            UnityEngine.Debug.LogError("Failed to copy exposed references. Could not find: " + oldExposedName);
                            continue;
                        }

                        var oldExposedValue = playableDirector.GetReferenceValue(oldExposedName, out isValid);

                        if (oldExposedValue != null && isValid)
                        {
                            // Replace exposedName on struct
                            var newExposedName = new PropertyName(GUID.Generate().ToString());
                            fieldInfo.FieldType.GetField("exposedName").SetValue(exposedReference, newExposedName);

                            // Set ExposedReference
                            fieldInfo.SetValue(newClip.asset, exposedReference);

                            // Set Reference on Playable Director
                            //UnityEngine.Debug.LogError("Valid: " + oldExposedName);
                            playableDirector.SetReferenceValue(newExposedName, oldExposedValue);
                        }
                        else
                        {
                            UnityEngine.Debug.LogError("Failed to copy exposed references. Could not find: " + oldExposedName);
                        }
                    }
                    else
                    {
                        
                    }
                }
            }
        }
        var prefabPath = "Assets/ResourcesAssets/Pve/Survivor/Prefabs/Timeline/" + newObject.name + ".prefab";
        PrefabUtility.SaveAsPrefabAsset(newObject,prefabPath);
        AssetDatabase.SaveAssets();
        AssetDatabase.Refresh();
        Selection.activeObject = AssetDatabase.LoadAssetAtPath<GameObject>(prefabPath);
        GameObject.DestroyImmediate(newObject);
    }

    private static void ClearExposedReference(PlayableDirector asset)
    {
        var type = asset.GetType();
        var serializedObject = new SerializedObject(asset);
        SerializedProperty property = serializedObject.FindProperty("m_ExposedReferences");
        var x = property.FindPropertyRelative("m_References");
        var count = x.arraySize;
        for (int i = 0; i < x.arraySize; i++)
        {
            //x.DeleteArrayElementAtIndex(0);
            var element = x.GetArrayElementAtIndex(i);
            var endOfChildrenIteration = element.GetEndProperty();
            bool isNull = false;
            object obj = null;
            string str = null;
            while (element.NextVisible(true) && !SerializedProperty.EqualContents(element, endOfChildrenIteration))
            {
                if (element.propertyType == SerializedPropertyType.ObjectReference)
                {
                    obj = element.objectReferenceValue;
                }
                else if (element.propertyType == SerializedPropertyType.String)
                {
                    str = element.stringValue;
                }
            }
            if (obj == null || str == null)
            {
                //BattleDebug.LogError("Null Object: ");
                x.DeleteArrayElementAtIndex(i);
                i--;
            }
            else
            {
                //BattleDebug.LogError("R: " + str + " " + obj);
            }
        }
        property = serializedObject.FindProperty("m_SceneBindings");
        count = property.arraySize;
        for (int i = 0; i < property.arraySize; i++)
        {
            //property.DeleteArrayElementAtIndex(0);
            var element = property.GetArrayElementAtIndex(i);
            var endOfChildrenIteration = element.GetEndProperty();
            bool isNull = false;
            while (element.NextVisible(true) && !SerializedProperty.EqualContents(element, endOfChildrenIteration))
            {
                if (element.propertyType == SerializedPropertyType.ObjectReference)
                {
                    if (element.objectReferenceValue == null)
                    {
                        isNull = true;
                        break;
                    }
                }
                else
                {
                    UnityEngine.Debug.LogError(element.name + " " + element.propertyType + " " + element.type);
                }
            }

            if (isNull)
            {
                //BattleDebug.LogError("Null Object: ");
                property.DeleteArrayElementAtIndex(i);
                i--;
            }
            /*var f = element.FindPropertyRelative("Key");
            var s = element.FindPropertyRelative("Second");
            BattleDebug.LogError(f);
            BattleDebug.LogError(f.name);
            BattleDebug.LogError(s);
            BattleDebug.LogError(s.name);*/
        }
        serializedObject.ApplyModifiedPropertiesWithoutUndo();
        /*ScriptableObject playableAsset = asset as ScriptableObject;
        var cloneObject = new SerializedObject(playableAsset);
        SerializedProperty prop = cloneObject.GetIterator();
        while (prop.Next(true))
        {
            if (prop.propertyType == SerializedPropertyType.ExposedReference && prop.isArray == false)
            {
                var exposedNameProp = prop.FindPropertyRelative("exposedName");
                var sourceKey = exposedNameProp.stringValue;
                var destKey = sourceKey;
                BattleDebug.LogError(sourceKey + " " + exposedNameProp);
            }
        }
        cloneObject.ApplyModifiedPropertiesWithoutUndo();*/
    }

    [MenuItem("GTATools/俯视角射击/创建编辑器脚本", false, 10)]
    public static void CreateEditorScript()
    {
        
    }
    
    [MenuItem("GTATools/俯视角射击/清理NavMesh", false, 10)]
    public static void ClearNavMesh()
    {
        NavMeshBakeHelper.Clear();
    }

    [MenuItem("GTATools/俯视角射击/导出NavMesh", false, 10)]
    public static void BakeNavmesh()
    {
        if (Selection.activeObject is GameObject go)
        {
            NavMeshBakeHelper.BakeNavMesh(go.transform);
            var navMeshData = NavMeshBakeHelper.navMesh;
            var path = "Assets/ResourcesAssets/Pve/Survivor/NavMesh/"+go.name+".asset";
            AssetDatabase.DeleteAsset(path);
            AssetDatabase.CreateAsset(navMeshData,path);
            AssetDatabase.SaveAssets();
            AssetDatabase.Refresh();
            EditorGUIUtility.PingObject(AssetDatabase.LoadAssetAtPath<NavMeshData>(path));
        }
        else
        {
            BattleDebug.LogError("未选择物体");
        }
    }
    
    //[MenuItem("GTATools/俯视角射击/导出Navmesh", false, 10)]
    public static void ExportSelectedNavmesh()
    {
        var prefab = NavMeshBakeHelper.CreateMeshObject();
        var path = "Assets/ResourcesAssets/Pve/Survivor/NavMesh/NavMesh.mesh";
        var meshFilter = prefab.GetComponentInChildren<MeshFilter>();
        AssetDatabase.CreateAsset(meshFilter.mesh, path);
        AssetDatabase.Refresh();
        var prefabPath = "Assets/ResourcesAssets/Pve/Survivor/Prefabs/MapData/NavMeshObject.prefab";
        meshFilter.mesh = AssetDatabase.LoadAssetAtPath<Mesh>(path);
        PrefabUtility.SaveAsPrefabAsset(prefab,prefabPath);
        AssetDatabase.Refresh();
    }
    
   private static string MeshToString(MeshFilter mf, Vector3 scale)
    {
        Mesh          mesh            = mf.sharedMesh;
        StringBuilder stringBuilder   = new StringBuilder().Append("mtllib design.mtl")
            .Append("\n")
            .Append("g ")
            .Append(mf.name)
            .Append("\n");
        Vector3[] vertices = mesh.vertices;
        for (int i = 0; i < vertices.Length; i++)
        {
            Vector3 vector = vertices[i];
            stringBuilder.Append(string.Format("v {0} {1} {2}\n", vector.x * scale.x, vector.y * scale.y, vector.z * scale.z));
        }
        stringBuilder.Append("\n");
        Dictionary<int, int> dictionary = new Dictionary<int, int>();
        if (mesh.subMeshCount > 1)
        {
            int[] triangles = mesh.GetTriangles(1);
            for (int j = 0; j < triangles.Length; j += 3)
            {
                if (!dictionary.ContainsKey(triangles[j]))
                {
                    dictionary.Add(triangles[j], 1);
                }
                if (!dictionary.ContainsKey(triangles[j + 1]))
                {
                    dictionary.Add(triangles[j + 1], 1);
                }
                if (!dictionary.ContainsKey(triangles[j + 2]))
                {
                    dictionary.Add(triangles[j + 2], 1);
                }
            }
        }
        for (int num = 0; num != mesh.uv.Length; num++)
        {
            Vector2 vector2 = mesh.uv[num];
            if (dictionary.ContainsKey(num))
            {
                stringBuilder.Append(string.Format("vt {0} {1}\n", mesh.uv[num].x, mesh.uv[num].y));
            }
            else
            {
                stringBuilder.Append(string.Format("vt {0} {1}\n", vector2.x, vector2.y));
            }
        }
        for (int k = 0; k < mesh.subMeshCount; k++)
        {
            stringBuilder.Append("\n");
            if (k == 0)
            {
                stringBuilder.Append("usemtl ").Append("Material_design").Append("\n");
            }
            if (k == 1)
            {
                stringBuilder.Append("usemtl ").Append("Material_logo").Append("\n");
            }
            int[] triangles2 = mesh.GetTriangles(k);
            for (int l = 0; l < triangles2.Length; l += 3)
            {
                stringBuilder.Append(string.Format("f {0}/{0} {1}/{1} {2}/{2}\n", triangles2[l] + 1, triangles2[l + 2] + 1, triangles2[l + 1] + 1));
            }
        }
        return stringBuilder.ToString();
    }


    [MenuItem("Assets/俯视角射击/LogCRC", false, 10)]
    public static void LogCRC()
    {
        var obj = Selection.objects[0];
        var path = AssetDatabase.GetAssetPath(obj);
        var filePath = Application.dataPath + path.Substring("Assets".Length);
        byte[] bytes = File.ReadAllBytes(filePath);
        int length = bytes.Length;
        int hashCode = Utility.Verifier.GetCrc32(bytes);
        UnityEngine.Debug.LogError(hashCode);
        string hashCodeHex = $"{hashCode:x8}";
        string folder = hashCodeHex.Substring(0, 2);
        var resourceName = $"data/{folder}/{hashCodeHex}";
        UnityEngine.Debug.LogError(resourceName);
    }
    
    [MenuItem("Assets/俯视角射击/检查多语言", false, 15)]
    public static void ExportLang()
    {
        string content = "";
        for (int i = 0; i < Selection.objects.Length; i++)
        {
            var obj = Selection.objects[i] as GameObject;
            var interactable = obj.GetComponentsInChildren<MapInteractableData>();
            var langKeyTag = obj.name;
            var hash = new HashSet<string>();
            for (int j = 0; j < interactable.Length; j++)
            {
                var data = interactable[j];
                if (data.events != null)
                {
                    for (int k = 0; k < data.events.Count; k++)
                    {
                        var item = data.events[k];
                        if (item.eventType == EBattleInteractableEvent.FlyText)
                        {
                            var param = item.param4;
                            var newKey = GetLangKey(langKeyTag,param,hash);
                            if (!string.IsNullOrEmpty(newKey) && param != newKey)
                            {
                                item.param4 = newKey;
                                content += $"{newKey} = {param}\n";
                            }
                        }
                        else if (item.eventType == EBattleInteractableEvent.ShowHud)
                        {
                            var param = item.param;
                            var newKey = GetLangKey(langKeyTag,param,hash);
                            if (!string.IsNullOrEmpty(newKey) && param != newKey)
                            {
                                item.param = newKey;
                                content += $"{newKey} = {param}\n";
                            }
                        }
                        else if (item.eventType == EBattleInteractableEvent.ShowBubble)
                        {
                            var param = item.param;
                            var newKey = GetLangKey(langKeyTag,param,hash);
                            if (!string.IsNullOrEmpty(newKey) && param != newKey)
                            {
                                item.param = newKey;
                                content += $"{newKey} = {param}\n";
                            }
                        }
                    }
                }
            }
            EditorUtility.SetDirty(obj);
        }
        AssetDatabase.SaveAssets();
        AssetDatabase.Refresh();
        BattleDebug.LogError(content);
    }

    private static string GetLangKey(string tag,string content,HashSet<string> map)
    {
        if (content.Contains(tag))
        {
            map.Add(content);
            return content;
        }

        for (int i = 0; i < 20; i++)
        {
            var key = tag + "_" + i;
            if (!map.Contains(key))
            {
                map.Add(key);
                return key;
            }
        }
        return String.Empty;
    }

    [MenuItem("Assets/俯视角射击/替换LightElement")]
    public static void ReplaceLightElement()
    {
        for (int i = 0; i < Selection.objects.Length; i++)
        {
            var obj = Selection.objects[i] as GameObject;
            var lightElements = obj.GetComponentsInChildren<LightElement>();
            for (int j = 0; j < lightElements.Length; j++)
            {
                var lightElement = lightElements[j];
                if (lightElement is SurvivorLightElement)
                {
                    continue;
                }

                var survivorElement = obj.AddComponent<SurvivorLightElement>();
                survivorElement.LightRenderers = new List<Renderer>();
                var lightRenderers = lightElement.LightRenderers;
                survivorElement.LightRenderers.AddRange(lightRenderers);
                survivorElement.CloneMaterial = lightElement.CloneMaterial;
                survivorElement.LightMaterials = lightElement.LightMaterials;
                survivorElement.controllerMark = lightElement.controllerMark;
                Object.DestroyImmediate(lightElement,true);
            }
            EditorUtility.SetDirty(obj);
        }
        AssetDatabase.SaveAssets();
        AssetDatabase.Refresh();
    }
    
    
    private class BuildAssetData
    {
        public string name;
        public string assetText;
        public string codeText;
        public int length;
    }

    [MenuItem("Assets/俯视角射击/替换shadow材质", false, 101999)]
    public static void ReplaceShadowMaterial()
    {
        for (int i = 0; i < Selection.objects.Length; i++)
        {
            var obj = Selection.objects[i] as GameObject;
            if (obj)
            {
                var modelInstaning = obj.GetComponentInChildren<ModelInstaning>();
                if (modelInstaning)
                {
                    var material = modelInstaning.shadowMat;
                    var path = AssetDatabase.GetAssetPath(material);
                    var mat = AssetDatabase.LoadAssetAtPath<Material>(path);
                    mat.shader = Shader.Find("GGame/HRP/MainCity/GPUSkinningShadowRpg");
                    EditorUtility.SetDirty(mat);
                }
            }
        }
        AssetDatabase.SaveAssets();
        AssetDatabase.Refresh();
    }
    

    [MenuItem("Assets/俯视角射击/检查二进制是否重复", false, 101999)]
    public static void CheckByteSame()
    {
        var map = new Dictionary<int, string>();
        for (int i = 0; i < Selection.objects.Length; i++)
        {
            //读取byte文件
            var path = AssetDatabase.GetAssetPath(Selection.objects[i]);
            var filePath = Application.dataPath + path.Substring("Assets".Length);
            var bytes = File.ReadAllBytes(filePath);
            var hash = Utility.Verifier.GetCrc32(bytes);
            if (map.TryGetValue(hash, out var value))
            {
                BattleDebug.LogError("重复 = " + path + ",应该使用 " + value);
            }
            else
            {
                map.Add(hash, path);
            }
        }
    }
    
    [MenuItem("GTATools/俯视角射击/对比BuildReport", false, 100999)]
    public static void CompareBuildReport()
    {
        var filePath1 = Application.dataPath.Replace("/Assets", "") + "/BuildReport_1.xml";
        var filePath2 = Application.dataPath.Replace("/Assets", "") + "/BuildReport_2.xml";
        var dic1 = GetBuildAssetData(filePath1);
        var dic2 = GetBuildAssetData(filePath2);
        var length = 0;
        var diffCount = 0;
        var unnecessaryCount = 0;
        foreach (var pair in dic1)
        {
            var data1 = pair.Value;
            if (dic2.TryGetValue(pair.Key, out var data2))
            {
                if (data1.codeText != data2.codeText)
                {
                    if (data1.assetText == data2.assetText)
                    {
                        BattleDebug.LogError(data2.name + /*"\n" + data1.assetText + "\n" + data2.assetText + */"\n" + data1.codeText + "\n" + data2.codeText);
                        length += data2.length;
                        unnecessaryCount++;
                    }
                    diffCount++;
                }
            }
        }
        BattleDebug.LogError("Diff = " + diffCount + " Same But Diff = " + unnecessaryCount+ " TotalLength = " + length);
    }

    
    [MenuItem("GameObject/俯视角射击/获取所有材质", false, 1)]
    public static void GetAllMaterials()
    {
        var obj = Selection.activeObject as GameObject;
        var shaderMap = new Dictionary<string, HashSet<string>>();
        var renderers = obj.GetComponentsInChildren<Renderer>();
        for (int i = 0; i < renderers.Length; i++)
        {
            var renderer = renderers[i];
            var sharedMaterials = renderer.sharedMaterials;
            for (int j = 0; j < sharedMaterials.Length; j++)
            {
                var material = sharedMaterials[j];
                if (material == null)
                {
                    continue;
                }
                var shader = material.shader;
                if (!shaderMap.TryGetValue(shader.name, out var value))
                {
                    value = new HashSet<string>();
                    shaderMap.Add(shader.name,value);
                }

                var keywords = material.shaderKeywords;
                for (int k = 0; k < keywords.Length; k++)
                {
                    if (!value.Contains(keywords[k]))
                    {
                        value.Add(keywords[k]);
                    }
                }
            }
        }

        foreach (var pair in shaderMap)
        {
            var content = "Shader = " + pair.Key + "\n";
            foreach (var keyword in pair.Value)
            {
                content += keyword + "\n";
            }
            BattleDebug.LogError(content);
        }
    }

    private static Dictionary<string, BuildAssetData> GetBuildAssetData(string path)
    {
        var dic = new Dictionary<string, BuildAssetData>();
        var doc = new XmlDocument();
        doc.Load(path);
        var nodes = doc.DocumentElement.ChildNodes;
        foreach (XmlNode node in nodes)
        {
            var nodes2 = node.ChildNodes;
            foreach (XmlNode node2 in nodes2)
            {
                if (node2.Name == "Resources")
                {
                    var nodes3 = node2.ChildNodes;
                    foreach (XmlNode node3 in nodes3)
                    {
                        var data = new BuildAssetData();
                        data.name = node3.Attributes["Name"].Value;
                        dic.Add(data.name,data);
                        var nodes4 = node3.ChildNodes;
                        foreach (XmlNode node4 in nodes4)
                        {
                            var nodeName = node4.Name;
                            if (nodeName == "Assets")
                            {
                                //BattleDebug.LogError("Asset = " + node4.Attributes["Count"].Value);
                                data.assetText = node4.OuterXml;
                            }
                            else if (nodeName == "Codes")
                            {
                                foreach (XmlNode node5 in node4.ChildNodes)
                                {
                                    if (node5.Name == "Android")
                                    {
                                        //BattleDebug.LogError("Codes = " + node5.Attributes["Length"].Value);
                                        data.codeText = node5.OuterXml;
                                        data.length = int.Parse(node5.Attributes["ZipLength"].Value);
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        return dic;
    }
}


